#include "StdAfx.h"
#include "StackWalker.h"

StackWalker::~StackWalker(void)
{
}

HRESULT StackWalker::WalkStack(CComPtr<ICorProfilerInfo2> pCorProfilerInfo)
{
	//OutputDebugStringA("StackWalk Start");
	m_pCorProfilerInfo = pCorProfilerInfo;	

	HRESULT hr = m_pCorProfilerInfo->DoStackSnapshot(NULL, StackWalkCallback, COR_PRF_SNAPSHOT_DEFAULT, this, NULL, 0);

	//OutputDebugStringA("StackWalk End");

	return hr;
}

STDMETHODIMP StackWalker::StackWalkCallback(FunctionID funcId, UINT_PTR ip, 
															 COR_PRF_FRAME_INFO frameInfo, 
															 ULONG32 contextSize, 
															 BYTE context[], void *clientData)
{
	if (funcId == 0)
	{
		// Unmanaged code, ignore
		return S_OK;
	}

	StackWalker *pStackWalker = static_cast<StackWalker *>(clientData);

	const ULONG32 typeArgsCount = 50;
	ULONG32 actualTypeArgsCount = 0;
	ClassID parentClassId;
	ModuleID moduleId;
	mdToken funcToken;

	ClassID typeArgs[typeArgsCount];
	
	HRESULT hr = pStackWalker->m_pCorProfilerInfo->GetFunctionInfo2(funcId, 
					frameInfo, &parentClassId, &moduleId, &funcToken, sizeof(typeArgs), &actualTypeArgsCount, typeArgs); 

	if (FAILED(hr))
		return E_FAIL;
	
	CComPtr<IMetaDataImport2> metaDataGetter = NULL;
	hr = pStackWalker->m_pCorProfilerInfo->GetModuleMetaData(moduleId, ofRead, IID_IMetaDataImport2, (IUnknown **)&metaDataGetter);

	if (FAILED(hr))
		return E_FAIL;

	CLRClass clrClass;
	pStackWalker->m_TypeTracker.GetCLRClassFor(parentClassId, &clrClass);

	WCHAR buf[512] = {};
	ULONG actualSize = 0;
	DWORD attributes = 0;
	PCCOR_SIGNATURE signature;
	ULONG signatureLength;
	ULONG rva;
	DWORD flags;
	mdTypeDef classToken;

	metaDataGetter->GetMethodProps(funcToken, &classToken, buf, sizeof(buf), &actualSize, &attributes, &signature, &signatureLength, &rva, &flags);

	std::wstring qualifiedName = clrClass.fullTypeName + std::wstring(L"::") + std::wstring(buf);

	//pFinalizerRunDetector->ofs << qualifiedName << std::endl;

	pStackWalker->m_CurrentStack.push_back(qualifiedName);
	return S_OK;
}
